﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

using Savorboard.CAP.InMemoryMessageQueue;

using Serilog;

using Swashbuckle.AspNetCore.SwaggerGen;

using Tszy.Unlimited.AspNetCore.Extensions;
using Tszy.Unlimited.Base;
using Tszy.Unlimited.Base.Extensions;

namespace Tszy.Unlimited.AspNetCore;

public static class AspNetCoreStartup
{
    /// <summary>
    /// 注册配置。
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="configPath">配置文件路径。</param>
    public static TszyAspNetCoreConfiguration RegisterTszyComponent(this WebApplicationBuilder builder, string configPath = "")
    {
        var configuration = builder.Services.GetConfiguration(builder.Environment.IsDevelopment(), configPath);

        builder.Configuration.AddConfiguration(configuration);

        // 允许同步读取IO流，否则无法同步读取 Request.Body。
        builder.Services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true);
        builder.Services.Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);
        builder.Services.RegisterTszyComponent(configuration);
        builder.RegisterSerilog(configuration);

        return new TszyAspNetCoreConfiguration(builder.Services, configuration);
    }

    /// <summary>
    /// 启用组件。
    /// </summary>
    /// <param name="app"></param>
    public static TszyAspNetCoreComponent UseTszyComponent(this WebApplication app)
    {
        // 解决 Ubuntu Nginx 代理不能获取IP问题
        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

        // 配置请求日志。
        app.UseSerilog();

        return new TszyAspNetCoreComponent(app);
    }

    /// <summary>
    /// 配置 MVC 模式返回的 JSON。
    /// </summary>
    /// <param name="builder"></param>
    public static IMvcBuilder ConfigureJson(this IMvcBuilder builder)
    {
        builder.AddNewtonsoftJson(options =>
        {
            //设置时间格式
            options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";

            //忽略循环引用
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

            //数据格式按原样输出
            options.SerializerSettings.ContractResolver = new DefaultContractResolver();
        });

        return builder;
    }
}

public class TszyAspNetCoreConfiguration
{
    private readonly IServiceCollection _services;
    private readonly IConfiguration _configuration;

    public IConfiguration Configuration => _configuration;
    public IServiceCollection Services => _services;

    public TszyAspNetCoreConfiguration(IServiceCollection services, IConfiguration configuration)
    {
        _services = services;
        _configuration = configuration;
    }

    public TszyAspNetCoreConfiguration RegisterSwagger(string title, string description = "", string version = "", Action<SwaggerGenOptions>? action = null)
    {
        _services.RegisterSwagger(title, description, version, action);
        return this;
    }

    public TszyAspNetCoreConfiguration RegisterCors()
    {
        _services.RegisterCors();
        return this;
    }

    public TszyAspNetCoreConfiguration SetBodyLength(int valueLengthLimit = int.MaxValue, int bodyLength = int.MaxValue, int headerLength = int.MaxValue)
    {
        // 配置文件大小限制
        _services.Configure<FormOptions>(options =>
        {
            options.ValueLengthLimit = valueLengthLimit;
            options.MultipartBodyLengthLimit = bodyLength;// 60000000;
            options.MultipartHeadersLengthLimit = headerLength;
        });

        return this;
    }

    /// <summary>
    /// 注册 CAP 模块。
    /// </summary>
    /// <remarks>
    /// 监控界面，访问：http://localhost:XXX/cap
    /// </remarks>
    /// <param name="services"></param>
    /// <returns></returns>
    public TszyAspNetCoreConfiguration RegisterCAP()
    {
        _services.AddCap(x =>
        {
            x.UseDashboard();   // 监控界面，访问：http://localhost:XXX/cap
            x.UseInMemoryStorage();
            x.UseInMemoryMessageQueue();
        });

        return this;
    }
}

public class TszyAspNetCoreComponent
{
    private readonly WebApplication _app;

    public TszyAspNetCoreComponent(WebApplication app)
    {
        _app = app;
    }

    /// <summary>
    /// 启用 Swagger 组件。
    /// </summary>
    /// <param name="isDevelopment">是否只有开发模式下才可显示。</param>
    /// <returns></returns>
    public TszyAspNetCoreComponent UseSwagger(bool isDevelopment = true)
    {
        _app.UseApiSwagger(isDevelopment);

        return this;
    }

    public TszyAspNetCoreComponent UseCors()
    {
        _app.UseCors();

        return this;
    }
}